#include "Vector.h"


#define ASSERT_OK_DEFINE if (!OK()) {dump (); assert ("OK failed");}

#define PUSH 1
#define ADD 2
#define SUB 3
#define MUL 4
#define DIV 5
#define PUSHX 6

template <typename T = int>
class Stack_t
{
protected:

    Vector_t<T> array_;

public:

    void push (T x)
    {
        ASSERT_OK_DEFINE
        array_.push_back(x);
    }

    T pop ()
    {
        ASSERT_OK_DEFINE
        T res = array_[array_.size() - 1];
        array_.pop_back();
        return res;
    }

    void Print ()
    {
        array_.Print();
    }

    bool OK()
    {
        return (array_.OK());
    }

    void dump()
    {
        array_.dump ("StackDump.txt");
    }
};


//??????????????????????????????????????????
class Proc_t : public Stack_t <int>
{
public:

    void add ()
    {
        int a = pop ();
        push (pop () + a);
    }

    void sub ()
    {
        int a = pop ();
        push (pop () - a);
    }

    void mul ()
    {
        int a = pop ();
        push (pop () * a);
    }

    void div ()
    {
        int a = pop ();
        push (pop () / a);
    }

    void clean ()
    {s
        array_.clean();
    }
};


class CPU_t
{
    Proc_t Proc;
    int x;
    Vector_t<int> program_;

public:

    void SetX (int ux)
    {
        x = ux;
    }

    int Run ()
    {
        Proc.clean ();
        for (int i = 0; i < program_.size(); i ++)
        {
            switch (program_ [i])
            {
                case PUSHX: Proc.push (x); break;
                case ADD: Proc.add (); break;
                case SUB: Proc.sub (); break;
                case MUL: Proc.mul (); break;
                case DIV: Proc.div (); break;
            }
            if (program_ [i] == PUSH)
            {
                i ++;
                Proc.push (program_ [i]);
            }
        }
        return Proc.pop ();
    }

    CPU_t ():
        Proc (),
        program_ (),
        x (0)
        {
        }

    CPU_t (char* name):
        Proc (),
        program_ (),
        x (0)
    {
        FILE *Ffrom = fopen (name, "r");
        int tmp;
        while (!feof(Ffrom))
        {
            fscanf (Ffrom, "%d\n", &tmp);
            program_.push_back(tmp);
        }
        fclose (Ffrom);
    }
};


void Asm (char *from, char *to)
{
    FILE *Ffrom = fopen (from, "r");
    FILE *Fto = fopen (to, "w");

    char tmp [20];
    int wrt = 0;
    while (!feof(Ffrom))
    {
        wrt = 0;
        fscanf (Ffrom, "%s", tmp);
        if (strcmp (tmp, "push") == 0)
        {
            fscanf (Ffrom, "%s", tmp);
            if (strcmp (tmp, "x") == 0) fprintf (Fto, "%d\n", PUSHX);
            else
            {
                fprintf (Fto, "%d\n%d\n", PUSH, Atoi (tmp));
            }
        }
        else
        {
            if (strcmp (tmp, "add") == 0) wrt = ADD;
            if (strcmp (tmp, "sub") == 0) wrt = SUB;
            if (strcmp (tmp, "mul") == 0) wrt = MUL;
            if (strcmp (tmp, "div") == 0) wrt = DIV;
            if (strcmp (tmp, "end") == 0) wrt = 0;
            fprintf (Fto, "%d\n", wrt);
            if (wrt == 0) break;
        }
    }

    fclose (Ffrom);
    fclose (Fto);
}


void DisAsm (char *from, char *to)
{
    FILE *Ffrom = fopen (from, "r");
    FILE *Fto = fopen (to, "w");

    int tmp;
    while (!feof(Ffrom))
    {
        fscanf (Ffrom, "%d\n", &tmp);
        if (tmp == PUSH)
        {
            fscanf (Ffrom, "%d\n", &tmp);
            fprintf (Fto, "push %d\n", tmp);
        }
        else
        {
            if (tmp == ADD) fprintf (Fto, "add\n");
            if (tmp == SUB) fprintf (Fto, "sub\n");
            if (tmp == MUL) fprintf (Fto, "mul\n");
            if (tmp == DIV) fprintf (Fto, "div\n");
            if (tmp == PUSHX) fprintf (Fto, "push x\n");
            if (tmp == 0) fprintf (Fto, "end");
        }
    }
    fclose (Ffrom);
    fclose (Fto);
}

int main ()
{
/*    Proc_t p;
    p.push (14);
    p.push (7);
    p.push (1);
    p.add ();
    p.sub ();
    p.Print();*/
    Asm ("1.txt", "2.txt");
    CPU_t cpu ("2.txt");
    cpu.SetX (3);
    printf ("%d", cpu.Run ());
    DisAsm ("2.txt", "3.txt");
}
